/*
 * Created on Oct 3, 2004
 */
package org.vectrics.struts;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;

import org.apache.log4j.Logger;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.vectrics.NotAuthorizedException;
import org.vectrics.common.util.StringUtils;
import org.vectrics.hibernate.ThreadProperties;
import org.vectrics.provider.CoreServiceLocator;

/**
 * This class provides a common base class for all Struts action classes. This
 * class packages requests into a VectricsActionData class.
 * 
 * @author mmoore
 */

public abstract class VectricsStrutsAction extends Action {

    protected transient final Logger log = Logger.getLogger(this.getClass());

    public static String FORWARD_NOT_AUTHORIZED = "not.authorized";

    public static String FORWARD_SUCCESS = "success";

    public static String FORWARD_FAILURE = "failure";

    /**
     * Handle request from base class. Returns The forward code for the next
     * Struts mapping forward.
     */
    protected abstract String doExecute(VectricsActionData actionData) throws JspException;

    /**
     * Handle request from Struts framework and send to doExecute method. This
     * method wraps a transaction around the derived class's doExecute action.
     */
    @Override
    public final ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
            HttpServletResponse response) throws JspException {
        ActionForward forward = null;
        try {
            String forwardCode = null;

            if (log.isDebugEnabled()) {
                log.debug(this.getClass().getName() + ".execute() called (will call doExecute() of derived class)");
            }
            log
                    .debug("this.getClass().getName() - checking to see if parameter specifies that the current window should be closed");
            String closeOnSubmit = request.getParameter("closeWindowOnSubmit");
            log.debug("Parameter: closeWindowOnSubmit = " + closeOnSubmit);
            if (StringUtils.isNullOrBlank(closeOnSubmit) == false) {
                request.setAttribute("closeWindowOnSubmit", "true");
            }

            log.info("Looking up action...");

            try {
                Request vectricsRequest = HttpRequestConverter.convertRequest(request);
                VectricsActionData actionData = new VectricsActionData(vectricsRequest, mapping, form, response);
                log.info("Running struts action of class: " + this.getClass().getName());
                forwardCode = doExecute(actionData);
                ThreadProperties.forcedCommit();

                if (actionData.getErrors() != null) {
                    this.saveErrors(request, actionData.getErrors());
                }
            } catch (NotAuthorizedException notAuthEx) {
                log.warn("Not Authorized Exception executing struts action", notAuthEx);
                forwardCode = FORWARD_NOT_AUTHORIZED;
            } catch (Exception ex) {
                log.error("Exception executing struts action", ex);
                response.getWriter().write("<BR/>");
                response.getWriter().write(ex.getMessage());
                response.getWriter().write("<BR/>");
                response.getWriter().write("<BR/>");
                ex.printStackTrace(response.getWriter());
                response.getWriter().write("<BR/>");
                throw new JspException("Exception executing struts action", ex);
            }

            if ((forwardCode.equals("success")) || (forwardCode.equals("cancel"))) {
                log.debug("Check for 'closeWindow' parameter to see if forward should go to close window html");
                if (StringUtils.isNullOrBlank(request.getParameter("closeWindow")) == false) {
                    log.debug("Close window forward being built...");
                    forwardCode = "success.close.window";
                }
            }
            forward = mapping.findForward(forwardCode);

            if (log.isDebugEnabled()) {
                log.debug("Action forward = " + forwardCode);
                log.debug("Forward path:   " + forward.getPath());
                log.debug("Forward code:   " + forwardCode);
                log.debug("Forward name:   " + forward.getName());
                log.debug("Forward module: " + forward.getModule());
            }
        } catch (Exception ex) {
            forward = mapping.findForward("exception");
            log.error("Exception in VectricsStrutsAction", ex);
            request.setAttribute("exception", ex);
        } finally {
            ThreadProperties.setSystemUser(false);
        }
        return (forward);
    }

    /**
     * Returns the Locale specific phrase for the passed code.
     * 
     * @param code
     *            The code that determines the phrase that will be used.
     * @param locale
     *            The locale of the user.
     * @return
     */
    protected String getPhrase(String code, Locale locale) {
        return CoreServiceLocator.getPhraseProvider().getMessage(code, locale);
    }

    public Collection<String> getParametersWithPrefix(Request request, String prefix) {
        Set<String> params = new HashSet<String>();

        Iterator<String> names = request.getParameterNames().iterator();
        while (names.hasNext()) {
            String param = (String) names.next();
            if (param.startsWith(prefix)) {
                params.add(param);
            }
        }
        return (params);
    }

}
